package DEEPERsource.DEEPERsource.source.machinelearning.javaml;

import java.util.Arrays;
import java.util.Vector;

import net.sf.javaml.core.Complex;
import net.sf.javaml.core.Instance;
import net.sf.javaml.core.SimpleInstance;
import net.sf.javaml.utils.MathUtils;

public class ExtendableInstance implements Instance{
	
	private int hashCode = 0;

	private Vector<Double> values = null;

	private boolean classSet = false;

	private int classValue = 0;

	private double weight = 1;

	/**
	 * Copy constructor, this makes a deep copy of the Instance
	 * 
	 * @param instance
	 */
	@Deprecated
	public ExtendableInstance(Instance instance) {
		this(new Vector(Arrays.asList(instance.toArray())), instance.weight(), instance.isClassSet(),
				instance.classValue());

	}

	/**
	 * Copy constructor, this makes a deep copy of the Instance
	 * 
	 * @param instance
	 */
	public ExtendableInstance(ExtendableInstance instance) {
		this(instance.values, instance.weight(), instance.isClassSet(),
				instance.classValue());

	}

	public ExtendableInstance(Vector<Double> values) {
		this(values, 1, false, 0);
	}
	
	public ExtendableInstance(Vector<Double> values, int classValue) {
		this(values, 1.0, true, classValue);
	}

	public ExtendableInstance(Vector<Double> values, int classValue, double weight) {
		this(values, weight, true, classValue);
	}

	/**
	 * Create a new instance that has the weight and class value of the old
	 * instance, but has new values.
	 * 
	 * @param values
	 *            the new values
	 * @param old
	 *            the instance from which to take the weight, and class
	 *            information.
	 */
	public ExtendableInstance(Vector<Double> values, Instance old) {
		this(values, old.weight(), old.isClassSet(), old.classValue());
	}

	private ExtendableInstance(Vector<Double> values, double weight, boolean classSet,
			int classValue) {
		this.values = new Vector<Double>(values);
		this.weight = weight;
		this.classSet = classSet;
		this.classValue = classValue;
		this.hashCode = this.values.hashCode();

	}
	
	public void addValue(double val){
		values.add(val);
	}

	public double value(int index) {
		return values.get(index);
	}

	public int classValue() {
		return classValue;
	}

	public boolean isClassSet() {
		return classSet;
	}

	public boolean isCompatible(Instance instance) {
		return instance.size() == this.size();
	}

	public double weight() {
		return this.weight;
	}

	public void setWeight(float d) {
		this.weight = d;

	}

	public int size() {
		return values.size();
	}

	public double[] toArray() {
		double[] out = new double[values.size()];
		int i = 0;
		for(Double d : values){
			out[i++] = d.doubleValue();
		}
		return out;
	}

	public Complex getComplex(int index) {
		return new Complex(value(index), 0);
	}

	public Instance copy() {
		return new SimpleInstance(this);
	}
	
	@Override
	public boolean equals(Object obj) {
		Instance tmp = (Instance) obj;
		boolean equal = values.size() == tmp.size();
		int pos = 0;
		while (equal && pos < values.size()) {
			equal = equal && MathUtils.eq(values.get(pos), tmp.value(pos));
			pos++;
		}
		return equal;
	}

	@Override
	public int hashCode() {
		return hashCode;
	}

	@Override
	public String toString() {
		StringBuffer out = new StringBuffer();
		if (values.size() == 0)
			return "[]";
		out.append("[" + values.get(0));
		for (int i = 1; i < values.size(); i++) {
			out.append(";" + values.get(0));
		}
		out.append(";w:" + this.weight);
		if (this.classSet) {
			out.append(";C:" + this.classValue);
		}
		out.append("]");
		return out.toString();
	}


}
